#include "device.h"
#include "drv_gpio.h"
#include "device_types.h"
#include "stm32f4xx.h"
#include "stm32f4xx_ll_bus.h"
#include "stm32f4xx_ll_gpio.h"
#include "stm32f4xx_ll_rcc.h"
#include "stm32f4xx_ll_gpio.h"

#define GPIO_NUM_MAX 16

struct stm32f4xx_gpio_s gpio_list[16] = {
    {LL_GPIO_PIN_4,  GPIOA, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOA},  /* GPIO0 */
    {LL_GPIO_PIN_5,  GPIOA, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOA},  /* GPIO1 */
    {LL_GPIO_PIN_3,  GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO2 */
    {LL_GPIO_PIN_4,  GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO3 */
    {LL_GPIO_PIN_6,  GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO4 */
    {LL_GPIO_PIN_12, GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO5 */
    {LL_GPIO_PIN_13, GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO6 */
    {LL_GPIO_PIN_14, GPIOB, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOB},  /* GPIO7 */
    {LL_GPIO_PIN_13,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO8 */
    {LL_GPIO_PIN_14,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO9 */
    {LL_GPIO_PIN_15,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO10 */
    {LL_GPIO_PIN_0,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO11 */
    {LL_GPIO_PIN_1,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO12 */
    {LL_GPIO_PIN_2,  GPIOC, LL_GPIO_AF_0,LL_AHB1_GRP1_PERIPH_GPIOC},  /* GPIO13 */
    
};

static int stm32f4xx_gpio_init(struct lt_dev_s *dev)
{
	return 0;
}

static int stm32f4xx_gpio_open(struct lt_dev_s *dev, uint16_t flag)
{

	return 0;
}

static int32_t  stm32f4xx_gpio_read(struct lt_dev_s *dev, void *buffer, int size,int pos)
{

	return 0;
}

static int32_t  stm32f4xx_gpio_write(struct lt_dev_s *dev, void *buffer, int size,int pos)
{
    struct gpio_info_s *info = (struct gpio_info_s *)buffer;

    if(info->pin < 0 || info->pin >= GPIO_NUM_MAX){
        return -1;
    }

    if(gpio_list[info->pin].port == GPIOA || gpio_list[info->pin].port == GPIOB || \
       gpio_list[info->pin].port == GPIOC || gpio_list[info->pin].port == GPIOH ){

        if(info->status){
            LL_GPIO_SetOutputPin(gpio_list[info->pin].port, gpio_list[info->pin].pin);
        }else{
            LL_GPIO_ResetOutputPin(gpio_list[info->pin].port, gpio_list[info->pin].pin);
        }

        return 0;
    }

	return 0;
}

static int32_t  stm32f4xx_gpio_ioctl(struct lt_dev_s *dev, uint8_t cmd, void *args)
{
    struct gpio_info_s *info = (struct gpio_info_s *)args;
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(info->pin < 0 || info->pin >= GPIO_NUM_MAX){
        return -1;
    }

    if(cmd == LT_DEVICE_CTRL_CONFIG){
        if(gpio_list[info->pin].port == GPIOA || gpio_list[info->pin].port == GPIOB || \
                        gpio_list[info->pin].port == GPIOC || gpio_list[info->pin].port == GPIOH ){

            LL_AHB1_GRP1_EnableClock(gpio_list[info->pin].clock);

            if(info->mode == GPIO_MODE_OUTPUT){
                GPIO_InitStruct.Mode       = LL_GPIO_MODE_OUTPUT;
                GPIO_InitStruct.Speed      = LL_GPIO_SPEED_FREQ_HIGH;
                GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
                GPIO_InitStruct.Pull       = LL_GPIO_PULL_NO;

                GPIO_InitStruct.Pin = gpio_list[info->pin].pin;
                LL_GPIO_Init(gpio_list[info->pin].port, &GPIO_InitStruct);

                if(info->status){
                    LL_GPIO_SetOutputPin(gpio_list[info->pin].port, gpio_list[info->pin].pin);
                }else{
                    LL_GPIO_ResetOutputPin(gpio_list[info->pin].port, gpio_list[info->pin].pin);
                }
            }
            return 0;
        }
    }

    return -1;
}

struct lt_dev_s stm32f4xx_gpio_dev;

int stm32f4xx_gpio_register(void)
{
	stm32f4xx_gpio_dev.init  = stm32f4xx_gpio_init;
    stm32f4xx_gpio_dev.open  = stm32f4xx_gpio_open;
	stm32f4xx_gpio_dev.read  = stm32f4xx_gpio_read;
	stm32f4xx_gpio_dev.write = stm32f4xx_gpio_write;
    stm32f4xx_gpio_dev.ioctl = stm32f4xx_gpio_ioctl;
	
	lt_dev_register(&stm32f4xx_gpio_dev,"gpio",O_RDWR);
	return 0;
}

